/* nrf24l01.c */
#include "nrf24l01.h"

/* STATUS Bit Fields */
#define STATUS_RX_DR_MASK           0x40u 
#define STATUS_TX_DS_MASK           0x20u
#define STATUS_MAX_RT_MASK          0x10u
#define STATUS_RX_P_NO_SHIFT        1
#define STATUS_RX_P_NO_MASK         0x0Eu
#define STATUS_RX_P_NO(x)           (((uint8_t)(((uint32_t)(x))<<STATUS_RX_P_NO_SHIFT))&STATUS_RX_P_NO_MASK)
#define STATUS_TX_FULL              0x01u
/* CONFIG bit Fields */
#define CONFIG_PRIM_RX_MASK         0x01u
#define CONFIG_PWR_UP_MASK          0x02u
#define CONFIG_CRCO_MASK            0x04u
#define CONFIG_EN_CRC_MASK          0x08u
#define CONFIG_MASK_MAX_RT_MASK     0x10u
#define CONFIG_MASK_TX_DS_MASK      0x20u
#define CONFIG_MASK_RX_DS_MASK      0x40u
/* OBSERVE_TX bit Fields */
#define OBSERVE_TX_ARC_CNT_MASK     0x0Fu
#define OBSERVE_TX_ARC_CNT_SHIFT    0
#define OBSERVE_TX_PLOS_CNT_MASK    0xF0u
#define OBSERVE_TX_PLOS_CNT_SHIFT   4
//********************************************************************************************************************// 
/* SPI(nRF24L01) æŒ‡ä»¤ */
#define READ_REG                    0x00   // è¯»é…ç½®å¯„å­˜å™¨
#define WRITE_REG                   0x20   // å†™é…ç½®å¯„å­˜å™¨
#define RD_RX_PLOAD                 0x61   // è¯»å–RX FIFOä¸­çš„æ•°æ®
#define WR_TX_PLOAD                 0xA0   // å‘TX FIFOä¸­å†™å…¥æ•°æ®
#define FLUSH_TX                    0xE1   // æ¸…é™¤TX FIFOä¸­çš„æ•°æ® åº”ç”¨äºŽå‘å°„æ¨¡å¼ä¸‹
#define FLUSH_RX                    0xE2   // æ¸…é™¤RX FIFOä¸­çš„æ•°æ® åº”ç”¨äºŽæŽ¥æ”¶æ¨¡å¼ä¸‹
#define REUSE_TX_PL                 0xE3   // é‡æ–°ä½¿ç”¨ä¸Šä¸€åŒ…æœ‰æ•ˆæ•°æ®
#define R_RX_PL_WID                 0x60
#define NOP                         0xFF   // ä¿ç•™
//********************************************************************************************************************// 
/* register define */
#define CONFIG              0x00  //é…ç½®å‘é€çŠ¶æ€ï¼ŒCRCæ ¡éªŒæ¨¡å¼ä»¥åŠå‘æ”¶å‘çŠ¶æ€å“åº”æ–¹å¼
#define EN_AA               0x01  //è‡ªåŠ¨åº”ç­”åŠŸèƒ½è®¾ç½®
#define EN_RXADDR           0x02  //å¯ç”¨ä¿¡é“è®¾ç½®
#define SETUP_AW            0x03  //æ”¶å‘åœ°å€å®½åº¦è®¾ç½®
#define SETUP_RETR          0x04  //è‡ªåŠ¨é‡å‘åŠŸèƒ½è®¾è®¾ç½®
#define RF_CH               0x05  //å·¥ä½œé¢‘çŽ‡è®¾å®š
#define RF_SETUP            0x06
#define STATUS              0x07
#define OBSERVE_TX          0x08 //å‘é€æ£€æµ‹å¯„å­˜å™¨
#define CD                  0x09
#define RX_ADDR_P0          0x0A
#define RX_ADDR_P1          0x0B
#define RX_ADDR_P2          0x0C
#define RX_ADDR_P3          0x0D
#define RX_ADDR_P4          0x0E
#define RX_ADDR_P5          0x0F
#define TX_ADDR             0x10
#define RX_PW_P0            0x11
#define RX_PW_P1            0x12
#define RX_PW_P2            0x13
#define RX_PW_P3            0x14
#define RX_PW_P4            0x15
#define RX_PW_P5            0x16
#define FIFO_STATUS         0x17
#define PYNPD               0x1C
#define FEATURE             0x1D

#define RX_PLOAD_WIDTH      32U /* Rx frame data length. */
#define TX_PLOAD_WIDTH      32U /* Tx frame data length. */
#define TX_ADR_WIDTH        5U
#define RX_ADR_WIDTH        5U

#define NRF24L01_CE_HIGH() NRF24L01_HW_GpioSetCEPin(true)
#define NRF24L01_CE_LOW()  NRF24L01_HW_GpioSetCEPin(false)

/* Adapter functions from hardware. */
static void NRF24L01_SPI_Write(uint8_t *txBufPtr, uint32_t txLen, bool csRetInactive);
static void NRF24L01_SPI_Read(uint8_t *rxBufPtr, uint32_t rxLen, bool csRetInactive);

/* Internal functions. */
static uint8_t NRF24L01_ReadRegister(uint8_t addr);
static void NRF24L01_WriteRegister(uint8_t addr, uint8_t val);
static void NRF24L01_WriteBuffer(uint8_t addr, uint8_t *buf, uint32_t len);
static void NRF24L01_ReadBuffer(uint8_t addr, uint8_t *buf, uint32_t len);

/* Check the device if attached to the bus. */
static bool NRF24L01_Probe(void)
{
    uint8_t i;
    uint8_t buf[5] = {0xA5,0xA5,0xA5,0xA5,0xA5};
    bool bRet = true;

    NRF24L01_WriteBuffer(WRITE_REG+TX_ADDR, buf, 5U);

    /* Clear the buffer to make sure the reveived values are new. */
    for (i = 0U; i < 5U; i++)
    {
        buf[i] = 0U;
    }
    NRF24L01_ReadBuffer(TX_ADDR, buf, 5U);

    for (i = 0; i < 5; i++)
    {
        if( buf[i] != 0xA5)
        {
            bRet = false;
            break;
        }
    }
    return bRet;
}

bool NRF24L01_Init(NRF24L01_Config_T *configPtr)
{
    NRF24L01_HW_InitIO();

    if (!NRF24L01_Probe())
    {
        return false;
    }

    NRF24L01_CE_LOW();
    
    NRF24L01_WriteRegister(WRITE_REG+CONFIG, 0x0F);
    NRF24L01_WriteRegister(WRITE_REG+EN_AA, 0x01); /* enable channel 0  auto ack. */
    NRF24L01_WriteRegister(WRITE_REG+EN_RXADDR, 0x01); /* enable channel 0 rx address. */
    NRF24L01_WriteRegister(WRITE_REG+SETUP_AW, 0x03); /* setup address width = 5byte. */
    NRF24L01_WriteRegister(WRITE_REG+SETUP_RETR, 0x1A);/* setup auto resend interval: 500us + 86us, 10 times max. */
    NRF24L01_WriteRegister(WRITE_REG+RF_CH, 40);/* set RF frequency. */
    NRF24L01_WriteRegister(WRITE_REG+RF_SETUP, 0x07); /* set tx parameter: 0db tx gain, 1Mbps, enable LNA.*/
    NRF24L01_WriteRegister(WRITE_REG+RX_PW_P0, RX_PLOAD_WIDTH); /* set channel 0 rx frame's data len, 32 byre. */
    NRF24L01_WriteBuffer(WRITE_REG+TX_ADDR, (uint8_t*)(configPtr->TxAddr), TX_ADR_WIDTH); /* Tx address. */
    NRF24L01_WriteBuffer(WRITE_REG+RX_ADDR_P0, (uint8_t*)(configPtr->RxAddr), RX_ADR_WIDTH); /*Rx address.*/

    NRF24L01_CE_HIGH();

    return true;
}

/*
 The default work mode is Rx. So before and after the Tx process, Rx is default work mode.
 only when in tx process, the work mode is set to be Tx mode.
*/
bool NRF24L01_TxPackage(uint8_t *txBufPtr)
{
    bool bRet = false;
    uint8_t sta;

    NRF24L01_CE_LOW();

    NRF24L01_WriteRegister(WRITE_REG+CONFIG, 0x0E); /* Tx mode. PRIM_RX = 0.*/
    /* write data to tx buffer. */
    NRF24L01_WriteBuffer(WR_TX_PLOAD, txBufPtr, TX_PLOAD_WIDTH);
    
    NRF24L01_CE_HIGH(); /* Launch the transfer.*/

    /* The tx process will be launched 10us after CE is pull up to high. */
    NRF24L01_WaitXferDone();

    /* Check the flags. */
    sta = NRF24L01_ReadRegister(STATUS);  /* Read status. */     
    NRF24L01_WriteRegister(WRITE_REG+STATUS, sta); /* Clear flags. */
    if (sta & STATUS_MAX_RT_MASK) /* Reach the max re-send time. */
    {
        NRF24L01_WriteRegister(FLUSH_TX,0xFF); /* Clear tx FIFO. */ 
        bRet = false; 
    }
    else if (sta & STATUS_TX_DS_MASK)/* Send succeed. */
    {
        bRet = true;
    }
    
    /* return to default Rx mode. PRIM_RX = 1.*/
    NRF24L01_WriteRegister(WRITE_REG+CONFIG, 0x0F); 
    return bRet;
}

bool NRF24L01_GetRxPackageReadyFlag(void)
{
    return (STATUS_RX_DR_MASK == (STATUS_RX_DR_MASK & NRF24L01_ReadRegister(STATUS)));
}

void NRF24L01_GetRxPackage(uint8_t *rxBufPtr)
{
    /* Read data from device. */
    NRF24L01_ReadBuffer(RD_RX_PLOAD, rxBufPtr, RX_PLOAD_WIDTH);
}

void NRF24L01_ClearRxPackageReadyFlag(void)
{
    NRF24L01_WriteRegister(WRITE_REG+STATUS, STATUS_RX_DR_MASK); /* Clear flags. */
    NRF24L01_WriteRegister(FLUSH_RX, 0xFF); /* Clear the rx FIFO. */
}

/* The IRQ pin will be logic zero in case:
 * - Get the ACK when finshing tx process.
 * - Receive the data when in rx process.
 * - Re-send too much.
*/
void NRF24L01_WaitXferDone(void)
{
    bool bRet;

    while (1)
    {
        bRet = NRF24L01_HW_GpioGetIrqPin();
        if (bRet == false)
        {
            break;
        }
    }
}

/****************************************************************************
 * Internal Functions.
 ***************************************************************************/
/* Hardware Adapter. */
static void NRF24L01_SPI_Write(uint8_t *txBufPtr, uint32_t txLen, bool enKeepCs)
{
    //return (sNrf24L01OpsPtr->SpiTxFunc)(txBufPtr, txLen, enKeepCs);
    uint32_t i;

    for (i = 0U; i < txLen-1U; i++)
    {
        NRF24L01_HW_SpiSwapData(txBufPtr[i], true);
    }
    NRF24L01_HW_SpiSwapData(txBufPtr[i], enKeepCs);
}

static void NRF24L01_SPI_Read(uint8_t *rxBufPtr, uint32_t rxLen, bool enKeepCs)
{
    uint32_t i;
    
    //return (sNrf24L01OpsPtr->SpiRxFunc)(rxBufPtr, rxLen, enKeepCs);
    for (i = 0U; i < rxLen-1U; i++)
    {
        rxBufPtr[i] = NRF24L01_HW_SpiSwapData(0xFF, true);
    }
    rxBufPtr[i] = NRF24L01_HW_SpiSwapData(0xFF, enKeepCs);
}

/* Read value from register. */
static uint8_t NRF24L01_ReadRegister(uint8_t addr)
{
    uint8_t tmp = addr;

    NRF24L01_SPI_Write(&tmp, 1U, true);
    NRF24L01_SPI_Read(&tmp, 1U, false);

    return tmp;
}

/* Write value to register. */
static void NRF24L01_WriteRegister(uint8_t addr, uint8_t val)
{
    uint8_t tmp;

    tmp = addr;
    NRF24L01_SPI_Write(&tmp, 1U, true);
    //NRF24L01_SPI_Read(&tmp, 1U, false);
    tmp = val;
    NRF24L01_SPI_Write(&tmp, 1U, false);
}

/* Read data from rx FIFO. */
static void NRF24L01_ReadBuffer(uint8_t addr, uint8_t *buf, uint32_t len)
{
    uint8_t tmp = addr;

    NRF24L01_SPI_Write(&tmp, 1U, true);
    NRF24L01_SPI_Read(buf, len, false);
}

/* Send data to tx FIFO. */
static void NRF24L01_WriteBuffer(uint8_t addr, uint8_t *buf, uint32_t len)
{
    uint8_t tmp = addr;

    NRF24L01_SPI_Write(&tmp, 1U, true);
    NRF24L01_SPI_Write(buf, len, false);
}

/* EOF. */

